;定义常量
DISK_BUFFER equ 0x7e00 ;临时存放数据用的缓存区，放到boot程序之后。0x7e00~0x7fff。

org 0x7c00

;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向与cs相同的段

mov esi,1 ;读取硬盘的第2个扇区
mov di,DISK_BUFFER
call func_read_one_sector

stop:
hlt
jmp stop 

;读取硬盘1个扇区（主硬盘控制器主盘）
;输入参数：esi，ds:di。
;esi LBA扇区号
;ds:di 将数据写入到的内存起始地址
;输出参数：无。
func_read_one_sector:
;第1步：检查硬盘控制器状态
mov dx,0x1f7
.not_ready1:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0xc0 ;第7位为1表示硬盘忙，第6位为1表示硬盘控制器已准备好，正在等待指令。
cmp al,0x40 ;当第7位为0，且第6位为1，则进入下一个步。
jne .not_ready1 ;若未准备好，则继续判断。
;第2步：设置要读取的扇区数
mov dx,0x1f2
mov al,1
out dx,al ;读取1个扇区
;第3步：将LBA地址存入0x1f3~0x1f6
mov eax,esi
;LBA地址7~0位写入端口0x1f3
mov dx,0x1f3
out dx,al
;LBA地址15~8位写入端口写入0x1f4
shr eax,8
mov dx,0x1f4
out dx,al
;LBA地址23~16位写入端口0x1f5
shr eax,8
mov dx,0x1f5
out dx,al
;第4步：设置device端口
shr eax,8
and al,0x0f ;LBA第24~27位
or al,0xe0 ;设置7~4位为1110，表示LBA模式，主盘
mov dx,0x1f6
out dx,al
;第5步：向0x1f7端口写入读命令0x20
mov dx,0x1f7
mov al,0x20
out dx,al
;第6步：检测硬盘状态
.not_ready2:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0x88 ;第7位为1表示硬盘忙，第3位为1表示硬盘控制器已准备好数据传输。
cmp al,0x08 ;当第7位为0，且第3位为1，进入下一步。
jne .not_ready2 ;若未准备好，则继续判断。
;第7步：从0x1f0端口读数据
mov cx,256 ;每次读取2字节，一个扇区需要读256次。
mov dx,0x1f0
.go_on_read:
in ax,dx
mov [di],ax
add di,2
loop .go_on_read
ret

times 510-($-$$) db 0
db 0x55,0xaa